home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
keymap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
11KB
|
447 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include "mutt_curses.h"
#include "keymap.h"
#include "mapping.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "functions.h"
/* contains the last key the user pressed */
int LastKey;
struct keymap_t *Keymaps[MENU_MAX];
static struct keymap_t *allocKeys (int len, keycode_t *keys)
{
struct keymap_t *p;
p = safe_calloc (1, sizeof (struct keymap_t));
p->len = len;
p->keys = safe_malloc (len * sizeof (keycode_t));
memcpy (p->keys, keys, len * sizeof (keycode_t));
return (p);
}
static struct mapping_t KeyNames[] = {
{ "pageup", KEY_PPAGE },
{ "pagedown", KEY_NPAGE },
{ "up", KEY_UP },
{ "down", KEY_DOWN },
{ "right", KEY_RIGHT },
{ "left", KEY_LEFT },
{ "delete", KEY_DC },
{ "backspace",KEY_BACKSPACE },
{ "insert", KEY_IC },
{ "home", KEY_HOME },
{ "end", KEY_END },
{ "enter", KEY_ENTER },
{ "return", M_ENTER_C },
{ NULL, 0 }
};
static int parsekeys (char *s, keycode_t *d, int max)
{
int n, len = max;
while (*s && len)
{
if ((n = mutt_getvaluebyname (s, KeyNames)) != -1)
{
s += strlen (s);
*d = n;
}
else if (tolower (*s) == 'f' && isdigit (*(s + 1)))
{
n = 0;
for (s++ ; isdigit (*s) ; s++)
{
n *= 10;
n += *s - '0';
}
*d = KEY_F(n);
}
else
{
*d = *s;
s++;
}
d++;
len--;
}
return (max - len);
}
/* insert a key sequence into the specified map. the map is sorted by ASCII
* value (lowest to highest)
*/
void km_bindkey (char *s, int menu, int op, char *macro)
{
struct keymap_t *map, *tmp, *last = NULL, *next;
keycode_t buf[MAX_SEQ];
int len, pos = 0, lastpos = 0;
len = parsekeys (s, buf, MAX_SEQ);
map = allocKeys (len, buf);
map->op = op;
map->macro = safe_strdup (macro);
tmp = Keymaps[menu];
while (tmp)
{
if (pos >= len || pos >= tmp->len)
{
/* map and tmp match, but have different lengths, so overwrite */
do
{
len = tmp->eq;
next = tmp->next;
if (tmp->macro)
free (tmp->macro);
free (tmp->keys);
free (tmp);
tmp = next;
}
while (tmp && len >= pos);
map->eq = len;
break;
}
else if (buf[pos] == tmp->keys[pos])
pos++;
else if (buf[pos] < tmp->keys[pos])
{
/* found location to insert between last and tmp */
map->eq = pos;
break;
}
else /* buf[pos] > tmp->keys[pos] */
{
last = tmp;
lastpos = pos;
if (pos > tmp->eq)
pos = tmp->eq;
tmp = tmp->next;
}
}
map->next = tmp;
if (last)
{
last->next = map;
last->eq = lastpos;
}
else
Keymaps[menu] = map;
}
static void push_string (char *s)
{
char *p = s + strlen (s) - 1;
while (p >= s)
mutt_ungetch (*p--);
}
static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey)
{
if (menu != MENU_EDITOR && menu != MENU_GENERIC && menu != MENU_PAGER)
{
if (lastkey)
mutt_ungetch (lastkey);
for (; keyslen; keyslen--)
mutt_ungetch (keys[keyslen - 1]);
return (km_dokey (MENU_GENERIC));
}
if (menu != MENU_EDITOR)
{
/* probably a good idea to flush input here so we can abort macros */
mutt_flushinp ();
}
return OP_NULL;
}
/* return values:
* >0 function to execute
* OP_NULL no function bound to key sequence
* -1 error occured while reading input
*/
int km_dokey (int menu)
{
struct keymap_t *map = Keymaps[menu];
int pos = 0;
int n = 0;
if (!map)
return (retry_generic (menu, NULL, 0, 0));
FOREVER
{
if ((LastKey = mutt_getch ()) == ERR)
return (-1);
while (LastKey > map->keys[pos])
{
if (pos > map->eq || !map->next)
return (retry_generic (menu, map->keys, pos, LastKey));
map = map->next;
}
if (LastKey != map->keys[pos])
return (retry_generic (menu, map->keys, pos, LastKey));
if (++pos == map->len)
{
if (map->op != OP_MACRO)
return (map->op);
if (n++ == 10)
{
mutt_flushinp ();
mutt_error ("Macro loop detected.");
return (-1);
}
push_string (map->macro);
map = Keymaps[menu];
pos = 0;
}
}
/* not reached */
}
static void create_bindings (struct binding_t *map, int menu)
{
int i;
for (i = 0 ; map[i].name ; i++)
if (map[i].seq)
km_bindkey (map[i].seq, menu, map[i].op, NULL);
}
char *km_keyname (int c)
{
static char buf[5];
switch (c)
{
case '\033':
return "ESC";
case ' ':
return "SPC";
case '\n':
case '\r':
return "RET";
case '\t':
return "TAB";
case KEY_UP:
return "Up";
case KEY_DOWN:
return "Down";
case KEY_LEFT:
return "Left";
case KEY_RIGHT:
return "Right";
case KEY_NPAGE:
return "PageDn";
case KEY_PPAGE:
return "PageUp";
case KEY_BACKSPACE:
return "BackSpace";
case KEY_HOME:
return "Home";
case KEY_END:
return "End";
case KEY_DC:
return "DEL";
case KEY_IC:
return "INS";
}
if (c < 256 && c > -128 && iscntrl ((unsigned char) c))
{
if (c < 0)
c += 256;
if (c < 128)
{
buf[0] = '^';
buf[1] = (c + '@') & 0x7f;
buf[2] = 0;
}
else
snprintf (buf, sizeof (buf), "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
}
else if (c >= KEY_F0 && c < KEY_F(256)) /* this maximum is just a guess */
sprintf (buf, "F%d", c - KEY_F0);
else if (IsPrint (c))
snprintf (buf, sizeof (buf), "%c", (unsigned char) c);
else
snprintf (buf, sizeof (buf), "\\x%hx", (unsigned short) c);
return (buf);
}
int km_expand_key (char *s, size_t len, struct keymap_t *map)
{
size_t l;
int p = 0;
if (!map)
return (0);
FOREVER
{
strfcpy (s, km_keyname (map->keys[p]), len);
len -= (1 + (l = strlen (s)));
if (++p >= map->len || !len)
return (1);
s += l;
*(s++) = ' ';
}
/* not reached */
}
struct keymap_t *km_find_func (int menu, int func)
{
struct keymap_t *map = Keymaps[menu];
for (; map; map = map->next)
if (map->op == func)
break;
return (map);
}
void km_init (void)
{
memset (Keymaps, 0, sizeof (struct keymap_t *) * MENU_MAX);
create_bindings (OpAlias, MENU_ALIAS);
create_bindings (OpAttach, MENU_ATTACH);
create_bindings (OpBrowser, MENU_FOLDER);
create_bindings (OpCompose, MENU_COMPOSE);
create_bindings (OpMain, MENU_MAIN);
create_bindings (OpPager, MENU_PAGER);
create_bindings (OpPost, MENU_POST);
#ifdef _PGPPATH
create_bindings (OpPgp, MENU_PGP);
#endif
/* bindings for the line editor */
create_bindings (OpEditor, MENU_EDITOR);
km_bindkey ("up", MENU_EDITOR, OP_EDITOR_HISTORY_UP, NULL);
km_bindkey ("down", MENU_EDITOR, OP_EDITOR_HISTORY_DOWN, NULL);
km_bindkey ("left", MENU_EDITOR, OP_EDITOR_BACKWARD_CHAR, NULL);
km_bindkey ("right", MENU_EDITOR, OP_EDITOR_FORWARD_CHAR, NULL);
km_bindkey ("home", MENU_EDITOR, OP_EDITOR_BOL, NULL);
km_bindkey ("end", MENU_EDITOR, OP_EDITOR_EOL, NULL);
km_bindkey ("backspace", MENU_EDITOR, OP_EDITOR_BACKSPACE, NULL);
km_bindkey ("delete", MENU_EDITOR, OP_EDITOR_BACKSPACE, NULL);
km_bindkey ("\177", MENU_EDITOR, OP_EDITOR_BACKSPACE, NULL);
/* generic menu keymap */
create_bindings (OpGeneric, MENU_GENERIC);
km_bindkey ("home", MENU_GENERIC, OP_FIRST_ENTRY, NULL);
km_bindkey ("end", MENU_GENER